#pragma once
#include "HashTableBase.h"
#include "DynamicList.h"

//----------------------------------------------------------------------------
// NOTE:
//
// The CDynamicList class was written by Arthur Liberman and is used in several
// of his other projects, both for his studies and his own public projects.
//----------------------------------------------------------------------------

// A HashTable class featuring a single-linked dynamic list as the bucket type
template <class Value>
class HashTableList : public HashTableBase<Value, CDynamicList<HashTableEntry<Value>>>
{
public:
	HashTableList(int i_Buckets = 1000);
	HashTableList(HashClass &i_HashClass, int i_Buckets = 1000);

	bool Add(char * i_Key, Value *i_Value);
	bool Remove(char * i_Key);
	HashTableEntry<Value> *GetEntry(char *i_Key, int i_Index = -1) const;	
};

template <class Value>
bool HashTableList<Value>::Add(char * i_Key, Value *i_Value)
{
	bool result = true;
	int index = this->GetIndex(i_Key);
	CDynamicList<HashTableEntry<Value>> *&bucket = this->m_Buckets[index];
	HashTableEntry<Value> *entry = new HashTableEntry<Value>(i_Key, i_Value, this->IsAutoFreeMemory());

	if (!bucket)
	{
		bucket = new CDynamicList<HashTableEntry<Value>>;
	}
	else
	{
		result = (this->GetEntry(i_Key, index) == NULL);
	}

	if (result)
	{
		this->m_ItemCount++;
		result = bucket->AddItem(entry) > 0;
	}

	if (!result)
	{
		delete entry;
		this->m_ItemCount--;
	}

	return result;
}

template <class Value>
bool HashTableList<Value>::Remove(char *i_Key)
{
	bool result = false;
	int index = this->GetIndex(i_Key);
	CDynamicList<HashTableEntry<Value>> *&bucket = this->m_Buckets[index];
	HashTableEntry<Value> *entry = this->GetEntry(i_Key, index);

	if (entry)
	{
		result = bucket->RemoveItem(entry);
		if (result)
		{
			this->m_ItemCount--;
		}

		if (bucket->ListCount() == 0)
		{
			delete bucket;
			bucket = NULL;
		}
	}

	return result;
}

template <class Value>
HashTableEntry<Value> *HashTableList<Value>::GetEntry(char *i_Key, int i_Index) const
{
	const bool v_FreeMemory = true;
	int index = (i_Index < 0) ? this->GetIndex(i_Key) : i_Index;
	CDynamicList<HashTableEntry<Value>> *bucket = this->m_Buckets[index];
	HashTableEntry<Value> *entry = new HashTableEntry<Value>(i_Key, NULL, !v_FreeMemory);
	HashTableEntry<Value> *existingEntry = NULL;

	if (bucket)
	{
		for (bucket->SelectFirst(); bucket->GetCurrent(); bucket->SelectNext())
		{
			if (*bucket->GetValue() == *entry)
			{
				existingEntry = bucket->GetValue();
				break;
			}
		}
	}

	delete entry;

	return existingEntry;
}

template <class Value>
HashTableList<Value>::HashTableList(HashClass &i_HashClass, int i_Buckets)
	: HashTableBase(i_HashClass, i_Buckets)
{
	this->EnableAutoFreeMemory(true);
}

template <class Value>
HashTableList<Value>::HashTableList(int i_Buckets)
	: HashTableBase(i_Buckets)
{
	this->EnableAutoFreeMemory(true);
}